import re
import requests
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.hashers import make_password
from django.db.models import Q
from geopy.distance import geodesic
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage, InvalidPage
from log.my_cache import lru_cache

# 用户
class User(AbstractUser):
    # 手机
    mobile = models.CharField(
        max_length=11, unique=True, db_column='手机', verbose_name='手机', help_text='手机')

    # 经度
    longitude = models.FloatField(
        default=-1, db_column='经度', verbose_name='经度', help_text='经度')

    # 纬度
    latitude = models.FloatField(
        default=-1, db_column='纬度', verbose_name='纬度', help_text='纬度')

    # 禁用
    is_forbid = models.BooleanField(
        default=False, db_column='是否禁用', verbose_name='是否禁用', help_text='是否禁用')

    # 自动回复
    is_auto_reply = models.BooleanField(
        default=True, db_column='是否自动回复', verbose_name='是否自动回复', help_text='是否自动回复')

    # 忙录值
    busy_score = models.IntegerField(
        default=0, db_column='忙录值', verbose_name='忙碌值', help_text='忙录值')

    display_field = ('id', 'username', 'is_staff',
                     'is_active', 'is_forbid', 'busy_score')

    class Meta:
        db_table = '用户'
        verbose_name_plural = verbose_name = db_table

    # 创建新的用户
    @classmethod
    def create_user(cls, mobile, password, longitude, latitude):

        # 创建新的user
        new_obj = cls()
        new_obj.mobile = mobile
        new_obj.password = make_password(password)
        new_obj.longitude = longitude
        new_obj.latitude = latitude
        new_obj.username = new_obj.mobile  # 初始时，用户名同账号
        new_obj.save()

    @classmethod
    def get_user_by_username(cls, username):
        return cls.objects.filter(Q(mobile=username) | Q(username=username)).first()

    @classmethod
    def get_by_pk(cls, pk):
        return cls.objects.filter(id=pk).first()

    # 在线用户
    @classmethod
    def get_online_users(cls, page, size):
        online_users = cls.objects.filter(
            Q(is_active=True) & Q(is_staff=False))
        paginator = Paginator(online_users, size)  # 创建分页对象，每页10条数据
        try:
            page_obj = paginator.page(page)  # 获取某一页的数据
        except (PageNotAnInteger, EmptyPage, InvalidPage):
            page_obj = paginator.page('1')  # 发生错误跳转到第一页

        return page_obj.object_list.values(*cls.display_field)

    # 获取可分配的客服，根据忙录值排序后，首先获取忙录值最低的在线客服，如果没有就选忙录值最低的不在线客服
    @classmethod
    def get_available_staff(cls):
        staffs = cls.objects.filter(is_staff=True).order_by('busy_score')
        online_staffs = staffs.filter(is_active=True)
        available_staff = online_staffs.first() or staffs.first()
        return {
            field: getattr(available_staff, field)
            for field in cls.display_field
        }

    # 计算两个地方之间的距离
    @staticmethod
    def get_distance(longitude_1, latitude_1, longitude_2, latitude_2):
        return geodesic((latitude_1, longitude_1), (latitude_2, longitude_2)).km

    # 获取指定范围内的用户
    def get_nearby_users(self, n, page, size):

        nearby_users = []
        for u in self.__class__.objects.all():
            distance = self.get_distance(
                self.longitude, self.latitude, u.longitude, u.latitude)
            if distance <= n:
                u.distance = distance
                nearby_users.append(u)

        paginator = Paginator(nearby_users, size)  # 创建分页对象，每页10条数据
        try:
            page_obj = paginator.page(page)  # 获取某一页的数据
        except (PageNotAnInteger, EmptyPage, InvalidPage):
            page_obj = paginator.page('1')  # 发生错误跳转到第一页

        data = []
        for u in page_obj.object_list:
            data.append(
                {
                    'id': u.id,
                    'username': u.username,
                    'longitude': u.longitude,
                    'latitude': u.latitude,
                    'distance': u.distance
                }
            )

        return data

    # 更新忙绿值
    def update_busy_score(self, score):
        self.busy_score += score
        return self.save()

    # 检测手机号码是否有效
    @staticmethod
    def is_valid_mobile(mobile):
        return re.match(r'1[3,4,5,7,8]\d{9}', mobile)

    # 检测用户名是否合法
    @staticmethod
    def is_valid_username(username):
        return len(username) <= 10 and re.match("^[A-Za-z0-9\u4e00-\u9fa5_]*$", username)

    # 检测手机号是否已注册
    @classmethod
    def is_exists_mobile(cls, mobile):
        return cls.objects.filter(mobile=mobile).exists()

    # 通过用户名获取用户
    @classmethod
    def get_by_username(cls, username):
        return cls.objects.filter(Q(mobile=username) | Q(username=username)).first()

    # 自动回复
    @staticmethod
    @lru_cache(size=128, expires_check=True, expires=60 * 60)
    def auto_reply(msg):
        robot_url = 'http://www.liulongbin.top:3006/api/robot?spoken={}'
        data = requests.get(robot_url.format(msg)).json()
        return data['data']['info']['text'] if data['message'] == 'success' else '您好，我暂时不在，有什么消息请留言。'

